﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Dokan;
using MirrorDrive.Operations;
using MirrorDrive.Operations.Cache;
using RemoteCode;
using SecureConnection;

namespace MirrorDrive.Client
{
    public class MirrorClient
    {
        private Nexum _nexum;
        private char _mountPoint;
        private bool mounted = false;

        public MirrorClient(string host, ushort port, byte[] key, string username, string password, char mountPoint)
        {
            _mountPoint = mountPoint;

            _nexum = new Nexum(false, key);
            _nexum.OnDisconnect += _nexum_OnDisconnect;
            _nexum.ConnectNexum(host, port);

            _nexum.CreateVariable("User Information", new string[] { username, password });
            _nexum.Pulse("InfoShared", timeOut:15000); //User info shared
            _nexum.Wait("Done", timeOut: 15000); //Wait for authorization            

            if (!EnsureDokanMount()) //Mount dokan
                throw new Exception("Unable to mount virtual harddrive!");
        }

        private bool EnsureDokanMount()
        {
            int status = DokanNet.DOKAN_SUCCESS;
            if (!new Action<Object>((object obj) =>
                {
                    DokanOptions opt = new DokanOptions();
                    opt.DebugMode = true;
                    opt.MountPoint = _mountPoint + ":\\";
                    opt.VolumeLabel = "Mirror Drive";
                    opt.ThreadCount = 5;
                    opt.RemovableDrive = true;

                    status = DokanNet.DokanMain(opt, new CacheOperations(new ClientOperations(_nexum)));
                }).BeginInvoke(null, null, null).AsyncWaitHandle.WaitOne(1500) && status != DokanNet.DOKAN_SUCCESS)
                return false;
            mounted = status == DokanNet.DOKAN_SUCCESS;
            return mounted;
        }

        public void Stop()
        {
            _nexum.Dispose();
        }

        private void _nexum_OnDisconnect(Nexum n, CloseReason reason)
        {
            if (mounted)
            {
                mounted = false;
                DokanNet.DokanUnmount(_mountPoint);
            }
        }
    }
}
